home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ian & Stuart's Australian Mac 1993 September
/
clonecd
/
September 93.img
/
Archives
/
Fun, Tricks & Hacks
/
Hacks & Tricks - CARE
/
Flipper
/
Flipper Code
/
flipScreen.c
< prev
next >
Wrap
Text File
|
1993-06-17
|
18KB
|
886 lines
/*
flipScreen.c
copyright © 1993 by Ken Hornak, Jr.
2120 Garden Homes Ct
Ann Arbor, MI 48103
GEnie: K.Hornak, AppleLink: MEDIMAGE
(I'm on AOL and CompuServe as well, but I forgot the accounts.)
Permission is granted to use this code in your programs as long
as the copyright is retained in the code. Please see the documentation
as to how we actually do the flip.
If you do something really cool with it, I hope you'll share it
with me. Some day I'd like to add vertical and diagonal axis flips
as well. It should also be made a small system extension instead of
a full app, but that can wait until another day.
Typical usage of this code would be:
setupToFlip(&myRec.myGlobals, FALSE);
flipIt(&myRec.myGlobals, 1, 2);
Delay(30, &ticksNow);
flipIt(&myRec.myGlobals, 1, 1);
cleanupFlip(&myRec.myGlobals);
killFlip(); // before exiting to remove the sleep task
Note that the code makes provision for segmenting the screen into
an array of panels and flipping those as well, however I seemed
to have broken that feature along the way somewhere and am not
going to fix it for a while.
I sincerely apologize for the strange state of this code, after all
it was written at MacHack and was truly thrown together with little
thought as to organization, commenting, parameter passing, naming,
you name it. This definitely does not reflect my day-to-day programming
(except for any bugs you may find).
*/
#include <stdio.h>
#include <GestaltEqu.h>
#include "flipScreen.h"
#define ROTATE_STEPS 20
#define abs(x) ((x) > 0 ? (x) : (-(x)))
#define RECT_HEIGHT(r) abs((r).bottom-(r).top)
#define RECT_WIDTH(r) abs((r).right-(r).left)
/*
Globals
*/
Boolean gHasPowerManager = FALSE;
MySleepInfo myRec;
/*
Prototypes
*/
GWorldPtr getScreen (void);
void getScreenRect (Rect* theRect);
void getScreenSection (ScreenPanel* thePanel, Rect* area);
void rotatePanel (ScreenPanel* thePanel, short h, short v, short how);
void rotatePanel2 (ScreenPanel* thePanel, short h, short v);
Boolean lockPanels (FlipInfo* gFlipGlobals);
/*
initFlipper
*/
void
initFlipper(void)
{
OSErr err = noErr;
long response;
myRec.myGlobals.gNumRows = 1;
myRec.myGlobals.gNumCols = 1;
myRec.myGlobals.gNumPanels = myRec.myGlobals.gNumRows *
myRec.myGlobals.gNumCols;
// Check for the Power Manager.
err = Gestalt(gestaltPowerMgrAttr, &response);
if (err == noErr)
{
if ((response >> gestaltPMgrExists) & 0x00000001)
gHasPowerManager = TRUE;
}
if (gHasPowerManager)
{
asm
{
move.l a5,myRec.myA5
}
// set up the record before installing onto the sleep queue
myRec.sleepRec.sleepQLink = 0;
myRec.sleepRec.sleepQType = slpQType; // sleep queue type, 16
myRec.sleepRec.sleepQProc = MySleepRtn; // address of some sleep routine
myRec.sleepRec.sleepQFlags = 0; // reserved field
SleepQInstall(&myRec.sleepRec); // install
}
} // initFlipper
/*
setupToFlip
*/
void
setupToFlip(FlipInfo* gFlipGlobals, Boolean grayScreen)
{
GrafPtr oldPort;
short i;
short rotateSteps;
CGrafPtr wPort;
Rect screenRect;
short curPanel;
Rect panelRect;
short j;
Boolean lockSuccess;
#ifdef DEBUG
unsigned char str[256];
#endif
GetPort(&oldPort);
GetCWMgrPort(&wPort);
getScreenRect(&screenRect);
rotateSteps = ROTATE_STEPS;
// Create the gworlds containing the screen sections.
curPanel = 0;
gFlipGlobals->gPanelHeight = RECT_HEIGHT(screenRect) / gFlipGlobals->gNumRows;
gFlipGlobals->gPanelWidth = RECT_WIDTH(screenRect) / gFlipGlobals->gNumCols;
for (i=0; i<gFlipGlobals->gNumRows; i++)
{
panelRect.top = screenRect.top + i * gFlipGlobals->gPanelHeight;
panelRect.bottom = panelRect.top + gFlipGlobals->gPanelHeight;
for (j=0; j<gFlipGlobals->gNumCols; j++)
{
panelRect.left = screenRect.left + j * gFlipGlobals->gPanelWidth;
panelRect.right = panelRect.left + gFlipGlobals->gPanelWidth;
if (j == gFlipGlobals->gNumCols-1)
panelRect.right = screenRect.right;
if (i == gFlipGlobals->gNumRows-1)
panelRect.bottom = screenRect.bottom;
#ifdef DEBUG
sprintf((char*) str, "ht: %hd, wd: %hd, l: %hd, t: %hd, r: %hd, b: %hd",
gFlipGlobals->gPanelHeight, gFlipGlobals->gPanelWidth,
panelRect.left, panelRect.top, panelRect.right, panelRect.bottom);
CtoPstr((char*) str);
DebugStr(str);
#endif
getScreenSection(&gFlipGlobals->gThePanels[curPanel], &panelRect);
curPanel++;
} // for j
} // for i
lockSuccess = lockPanels(gFlipGlobals);
if (!lockSuccess)
DebugStr("\pCouldn't lock the panels.");
SetPort((GrafPtr) wPort);
ClipRect(&wPort->portRect);
if (grayScreen)
{
// Make the whole screen gray.
FillRect(&wPort->portRect, gray);
}
SetPort(oldPort);
} // setupToFlip
/*
flipIt
*/
void
flipIt(FlipInfo* gFlipGlobals, short how, short direction)
{
GrafPtr oldPort;
short h;
short v;
CGrafPtr wPort;
short i;
short j;
short rotateStep;
short rotateSteps;
PixMapHandle pmap;
long thisRotateTime, rotateTime, numRotates;
#ifdef DEBUG
Str255 str;
#endif
GetPort(&oldPort);
GetCWMgrPort(&wPort);
rotateSteps = ROTATE_STEPS;
// Make sure the screen gets blanked.
SetPort((GrafPtr) wPort);
ForeColor(blackColor);
BackColor(whiteColor);
// Setup to rotate each section.
rotateStep = gFlipGlobals->gPanelHeight / rotateSteps;
HideCursor();
numRotates = 0;
if (direction == 1)
{
for (h=1; h<=gFlipGlobals->gPanelHeight; h+=rotateStep)
{
v = ((gFlipGlobals->gPanelHeight - h) * 3) / 4;
for (i=0; i<gFlipGlobals->gNumPanels; i++)
{
rotatePanel(&gFlipGlobals->gThePanels[i], h, v, how);
// Now blit the rotated section to the screen.
SetPort((GrafPtr) wPort);
pmap = gFlipGlobals->gThePanels[i].rotatedPMap;
CopyBits((BitMapPtr) *pmap, (BitMapPtr) *wPort->portPixMap,
&gFlipGlobals->gThePanels[i].rotatedGWorld->portRect,
&gFlipGlobals->gThePanels[i].itsGWorld->portRect, srcCopy, NULL);
} // for i
} // for h
// Finish by putting the exact image back.
for (i=0; i<gFlipGlobals->gNumPanels; i++)
{
// Now blit the correct section to the screen.
SetPort((GrafPtr) wPort);
pmap = GetGWorldPixMap(gFlipGlobals->gThePanels[i].itsGWorld);
if (LockPixels(pmap))
{
CopyBits((BitMapPtr) *pmap, (BitMapPtr) *wPort->portPixMap,
&gFlipGlobals->gThePanels[i].itsGWorld->portRect,
&gFlipGlobals->gThePanels[i].itsGWorld->portRect, srcCopy, NULL);
UnlockPixels(pmap);
}
} // for i
}
else
{
for (h=gFlipGlobals->gPanelHeight-rotateStep; h>0; h-=rotateStep)
{
v = ((gFlipGlobals->gPanelHeight - h) * 3) / 4;
for (i=0; i<gFlipGlobals->gNumPanels; i++)
{
rotatePanel(&gFlipGlobals->gThePanels[i], h, v, how);
// Now blit the rotated section to the screen.
SetPort((GrafPtr) wPort);
pmap = gFlipGlobals->gThePanels[i].rotatedPMap;
CopyBits((BitMapPtr) *pmap, (BitMapPtr) *wPort->portPixMap,
&gFlipGlobals->gThePanels[i].rotatedGWorld->portRect,
&gFlipGlobals->gThePanels[i].itsGWorld->portRect, srcCopy, NULL);
} // for i
} // for h
// Make the whole screen gray.
FillRect(&wPort->portRect, gray);
}
SetPort(oldPort);
ShowCursor();
} // flipIt
/*
cleanupFlip
*/
void
cleanupFlip(FlipInfo* gFlipGlobals)
{
short i;
// Dispose of everything.
for (i=0; i<gFlipGlobals->gNumPanels; i++)
{
DisposeGWorld(gFlipGlobals->gThePanels[i].itsGWorld);
gFlipGlobals->gThePanels[i].itsGWorld = NULL;
DisposeGWorld(gFlipGlobals->gThePanels[i].rotatedGWorld);
gFlipGlobals->gThePanels[i].rotatedGWorld = NULL;
}
} // cleanupFlip
/*
lockPanels
*/
Boolean
lockPanels(FlipInfo* gFlipGlobals)
{
short i;
for (i=0; i<gFlipGlobals->gNumPanels; i++)
{
gFlipGlobals->gThePanels[i].itsPMap =
GetGWorldPixMap(gFlipGlobals->gThePanels[i].itsGWorld);
if (!LockPixels(gFlipGlobals->gThePanels[i].itsPMap))
return(FALSE);
gFlipGlobals->gThePanels[i].rotatedPMap =
GetGWorldPixMap(gFlipGlobals->gThePanels[i].rotatedGWorld);
if (!LockPixels(gFlipGlobals->gThePanels[i].rotatedPMap))
return(FALSE);
} // for i
return(TRUE);
} // lockPanels
/*
rotatePanel
*/
void
rotatePanel(ScreenPanel* thePanel, short h, short v, short how)
{
PixMapHandle pmap;
CGrafPtr oldPort;
GDHandle gdh;
PixMapHandle rotatedPMap;
short width;
short height;
short row;
short col;
Rect theRect;
short x;
short y;
short midY;
short midX;
short y1, y2, deltaX;
Rect srcRect, dstRect;
Pattern myGray = { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 };
short bytesPerRow;
short bytesInDstRow;
Ptr srcPtr;
Ptr dstPtr;
short pixelDepth;
short realBytesPerRow;
pmap = thePanel->itsPMap;
// Get the current port settings.
GetGWorld(&oldPort, &gdh);
// Clear the destination gworld.
rotatedPMap = thePanel->rotatedPMap;
SetGWorld(thePanel->rotatedGWorld, thePanel->rotatedGDevice);
theRect = thePanel->itsGWorld->portRect;
ForeColor(blackColor);
BackColor(whiteColor);
FillRect(&theRect, myGray);
bytesPerRow = (**pmap).rowBytes & 0x3FFF;
srcPtr = GetPixBaseAddr(pmap);
dstPtr = GetPixBaseAddr(rotatedPMap);
pixelDepth = (**pmap).pixelSize;
realBytesPerRow = RECT_WIDTH(theRect) * (long) pixelDepth / 8L;
width = RECT_WIDTH(theRect);
height = RECT_HEIGHT(theRect);
midY = (theRect.top + theRect.bottom) / 2;
y1 = midY - h / 2;
y2 = y1 + h;
srcRect.left = theRect.left;
srcRect.right = theRect.right;
dstRect.top = y1;
dstRect.bottom = y1 + 1;
dstPtr += (long) y1 * (long) bytesPerRow;
for (row = y1; row <= y2; row++)
{
y = theRect.top + (long) height * (long) (row - y1) / h;
deltaX = (long) v * (long) (row - y1) / (2 * h);
dstRect.left = theRect.left + deltaX;
dstRect.right = theRect.right - deltaX;
srcRect.top = y;
srcRect.bottom = y + 1;
switch (how)
{
case 1: // w/block move from both edges
bytesInDstRow = (long) (dstRect.right - dstRect.left) * (long) pixelDepth / 8L;
// Copy first part of src line
BlockMove(srcPtr + (long) y * (long) bytesPerRow,
dstPtr + (long) deltaX * (long) pixelDepth / 8L,
bytesInDstRow / 2);
// Copy last part of src line
BlockMove(srcPtr + (long) y * (long) bytesPerRow + (realBytesPerRow - bytesInDstRow / 2),
dstPtr + (long) deltaX * (long) pixelDepth / 8L + bytesInDstRow / 2,
bytesInDstRow / 2);
dstPtr += bytesPerRow;
break;
case 3: // w/block move from left edge
bytesInDstRow = (long) (dstRect.right - dstRect.left) * (long) pixelDepth / 8L;
if (0) // copy from right
BlockMove(srcPtr + (long) y * (long) bytesPerRow + (realBytesPerRow - bytesInDstRow),
dstPtr + (long) deltaX * (long) pixelDepth / 8L,
bytesInDstRow);
else // copy from left
BlockMove(srcPtr + (long) y * (long) bytesPerRow,
dstPtr + (long) deltaX * (long) pixelDepth / 8L,
bytesInDstRow);
dstPtr += bytesPerRow;
break;
case 2: // w/copybits
CopyBits((BitMapPtr) *pmap, (BitMapPtr) *rotatedPMap,
&srcRect, &dstRect, srcCopy, NULL);
break;
default:
break;
} // switch
dstRect.top++;
dstRect.bottom++;
} // for row
SetGWorld(oldPort, gdh);
} // rotatePanel
/*
rotatePanel2
*/
void
rotatePanel2(ScreenPanel* thePanel, short h, short v)
{
PixMapHandle pmap;
short pixelSize;
short bytesPerRow;
short pixelsPerRow;
short unusedBytes;
CGrafPtr oldPort;
GDHandle gdh;
PixMapHandle rotatedPMap;
short width;
short height;
short row;
short col;
Rect theRect;
short x;
short y;
short midY;
short midX;
unsigned char* srcValPtr;
unsigned char* dstValPtr;
short y1, y2, deltaX;
Rect srcRect, dstRect;
// First we need to know how many bytes might be unused at the
// end of each row of pixels.
pmap = GetGWorldPixMap(thePanel->itsGWorld);
if (!LockPixels(pmap))
{
DebugStr("\pCouldn't lock pixels in rotate2.");
return;
}
#if 0
pixelSize = (**pmap).pixelSize;
bytesPerRow = (**pmap).rowBytes & 0x3FFF;
pixelsPerRow = RECT_WIDTH((**pmap).bounds);
unusedBytes = (long) bytesPerRow - (long) pixelSize * (long) pixelsPerRow / 8L;
#endif
// Get the current port settings.
GetGWorld(&oldPort, &gdh);
// Clear the destination gworld.
rotatedPMap = GetGWorldPixMap(thePanel->rotatedGWorld);
if (!LockPixels(rotatedPMap))
{
DebugStr("\pCouldn't lock rotated pixels in rotate2.");
return;
}
SetGWorld(thePanel->rotatedGWorld, thePanel->rotatedGDevice);
theRect = thePanel->itsGWorld->portRect;
BackColor(blackColor);
EraseRect(&theRect);
ForeColor(blackColor);
BackColor(whiteColor);
width = RECT_WIDTH(theRect);
height = RECT_HEIGHT(theRect);
midY = (theRect.top + theRect.bottom) / 2;
y1 = midY - h / 2;
y2 = y1 + h;
for (row = y1; row <= y2; row++)
{
y = theRect.top + (long) height * (long) (row - y1) / h;
deltaX = v * (y2 - row) / (2 * h);
dstRect.left = theRect.left + deltaX;
dstRect.right = theRect.right - deltaX;
dstRect.top = row;
dstRect.bottom = row + 1;
srcRect.left = theRect.left;
srcRect.right = theRect.right;
srcRect.top = y;
srcRect.bottom = y + 1;
#if 0
if (srcRect.top < theRect.top)
DebugStr("\psrcRect.top is too small.");
if (srcRect.bottom > theRect.bottom)
DebugStr("\psrcRect.bottom is too great.");
#endif
CopyBits((BitMapPtr) *pmap, (BitMapPtr) *rotatedPMap,
&srcRect, &dstRect, srcCopy, NULL);
} // for row
UnlockPixels(pmap);
UnlockPixels(rotatedPMap);
SetGWorld(oldPort, gdh);
} // rotatePanel2
/*
getScreenSection
*/
void
getScreenSection(ScreenPanel* thePanel, Rect* area)
{
GDHandle mainScreen = NULL;
QDErr err = noErr;
GWorldPtr theGWorld = NULL;
short pixelDepth;
CTabHandle cTable;
GWorldFlags flags;
GDHandle aGDevice;
GDHandle gdh;
CGrafPtr oldPort;
CGrafPtr wPort;
PixMapHandle gworldPMap;
Rect boundsRect;
GWorldPtr rotatedGWorld = NULL;
#ifdef DEBUG
Str255 str;
#endif
mainScreen = GetMainDevice();
aGDevice = mainScreen;
pixelDepth = (**(**mainScreen).gdPMap).pixelSize;
flags = noNewDevice | useTempMem;
cTable = (**(**mainScreen).gdPMap).pmTable;
boundsRect = *area;
err = NewGWorld(&theGWorld, pixelDepth, &boundsRect, cTable, aGDevice, flags);
if (err != noErr)
{
DebugStr("\pCouldn't create the gworld.");
return;
}
// Create an identical gworld to hold the rotated image.
err = NewGWorld(&rotatedGWorld, pixelDepth, &boundsRect, cTable, aGDevice, flags);
if (err != noErr)
{
DebugStr("\pCouldn't create the rotated gworld.");
return;
}
thePanel->rotatedGWorld = rotatedGWorld;
thePanel->rotatedGDevice = GetGWorldDevice(rotatedGWorld);
// Get the main gworld's gdevice.
aGDevice = GetGWorldDevice(theGWorld);
thePanel->itsGDevice = aGDevice;
GetGWorld(&oldPort, &gdh);
SetGWorld(theGWorld, aGDevice);
// Get the screen's port.
GetCWMgrPort(&wPort);
gworldPMap = GetGWorldPixMap(theGWorld);
if (!LockPixels(gworldPMap))
{
DebugStr("\pCouldn't lock pixels while grabbing a section.");
return;
}
// Copy the contents of the screen into the GWorld.
#ifdef DEBUG
sprintf((char*) str, "Copying from screen: l: %hd, t: %hd, r: %hd, b: %hd",
boundsRect.left, boundsRect.top, boundsRect.right, boundsRect.bottom);
CtoPstr((char*) str);
DebugStr(str);
#endif
CopyBits((BitMapPtr) *wPort->portPixMap, (BitMapPtr) *gworldPMap, &boundsRect, &boundsRect,
srcCopy, NULL);
UnlockPixels(gworldPMap);
SetGWorld(oldPort, gdh);
thePanel->itsGWorld = theGWorld;
} // getScreenSection
/*
getScreenRect
*/
void
getScreenRect(Rect* theRect)
{
GDHandle mainScreen = NULL;
mainScreen = GetMainDevice();
*theRect = (**mainScreen).gdRect;
} // getScreenRect
/*
getScreen
*/
GWorldPtr
getScreen(void)
{
GDHandle mainScreen = NULL;
QDErr err = noErr;
GWorldPtr theGWorld = NULL;
short pixelDepth;
CTabHandle cTable;
GWorldFlags flags;
GDHandle aGDevice;
GDHandle gdh;
CGrafPtr oldPort;
CGrafPtr wPort;
PixMapHandle gworldPMap;
Rect boundsRect;
mainScreen = GetMainDevice();
aGDevice = mainScreen;
pixelDepth = (**(**mainScreen).gdPMap).pixelSize;
flags = noNewDevice | useTempMem;
cTable = (**(**mainScreen).gdPMap).pmTable;
boundsRect = (**mainScreen).gdRect;
err = NewGWorld(&theGWorld, pixelDepth, &boundsRect, cTable, aGDevice, flags);
if (err != noErr)
return(NULL);
aGDevice = GetGWorldDevice(theGWorld);
GetGWorld(&oldPort, &gdh);
SetGWorld(theGWorld, aGDevice);
// Get the screen's port.
GetCWMgrPort(&wPort);
gworldPMap = GetGWorldPixMap(theGWorld);
if (!LockPixels(gworldPMap))
return(NULL);
// Copy the contents of the screen into the GWorld.
CopyBits((BitMapPtr) *wPort->portPixMap, (BitMapPtr) *gworldPMap, &boundsRect, &boundsRect,
srcCopy, NULL);
UnlockPixels(gworldPMap);
SetGWorld(oldPort, gdh);
return(theGWorld);
} // getScreen
/*
killFlip
*/
void
killFlip(void)
{
SleepQRemove(&myRec.sleepRec);
} // killFlip
/*
MySleepRtn
*/
long
MySleepRtn(void)
{
long reason;
MySleepInfo* info;
long theA5;
// D0 contains the reason we're being called.
asm
{
move.l D0,reason
move.l A0,info
}
theA5 = info->myA5;
asm
{
move.l theA5,a5
}
switch (reason)
{
case 1: // sleep request
case 2: // sleep demand
setupToFlip(&info->myGlobals, FALSE);
flipIt(&info->myGlobals, 1, 2);
break;
case 3: // wakeup demand
flipIt(&info->myGlobals, 1, 1);
cleanupFlip(&info->myGlobals);
break;
default:
break;
} // switch
return(0); // always succeed
} // MySleepRtn